/**
 * @file uart_common.c
 * @brief UART通用抽象层实现文件
 * 
 * 该模块实现统一的UART操作接口，消除各线程中重复的串口初始化代码。
 * 支持RS232和RS485两种串口类型，提供统一的配置和操作接口。
 * 
 * @author 伞控无人机项目组
 * @date 2024
 */

#include "uart_common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <linux/serial.h>

// 内部函数声明
static int set_baudrate(int fd, int baudrate);
static int set_termios_options(int fd, const uart_config_t *config);
static int configure_buffer_size(int fd, int target_size);

/**
 * @brief 获取默认UART配置
 * 
 * @param type 串口类型
 * @return uart_config_t 默认配置
 */
uart_config_t uart_get_default_config(uart_type_t type) {
    uart_config_t config = {
        .baudrate = UART_DEFAULT_BAUDRATE,
        .data_bits = UART_DEFAULT_DATA_BITS,
        .stop_bits = UART_DEFAULT_STOP_BITS,
        .parity = UART_DEFAULT_PARITY,
        .flow_control = UART_DEFAULT_FLOW_CONTROL,
        .timeout_ms = UART_DEFAULT_TIMEOUT_MS,
        .buffer_size = UART_DEFAULT_BUFFER_SIZE,
        .flags = 0
    };
    
    // 根据串口类型调整默认配置
    if (type == UART_TYPE_RS485) {
        // RS485通常使用较低波特率
        config.baudrate = 9600;
        config.timeout_ms = 200;  // RS485需要更长的超时时间
    }
    
    return config;
}

/**
 * @brief 初始化UART设备
 * 
 * @param device 设备路径 (如 "/dev/ttyS8")
 * @param type 串口类型
 * @param config 串口配置，如果为NULL则使用默认配置
 * @return int 成功返回文件描述符，失败返回错误代码
 */
int uart_init_device(const char *device, uart_type_t type, const uart_config_t *config) {
    // 参数检查
    if (device == NULL) {
        return UART_ERROR_INVALID_PARAM;
    }
    
    // 使用默认配置或合并配置
    uart_config_t final_config;
    if (config == NULL) {
        final_config = uart_get_default_config(type);
    } else {
        final_config = *config;
        // 如果某些参数未设置，使用默认值
        if (final_config.baudrate <= 0) final_config.baudrate = UART_DEFAULT_BAUDRATE;
        if (final_config.data_bits <= 0) final_config.data_bits = UART_DEFAULT_DATA_BITS;
        if (final_config.stop_bits <= 0) final_config.stop_bits = UART_DEFAULT_STOP_BITS;
        if (final_config.timeout_ms < 0) final_config.timeout_ms = UART_DEFAULT_TIMEOUT_MS;
        if (final_config.buffer_size <= 0) final_config.buffer_size = UART_DEFAULT_BUFFER_SIZE;
    }
    
    // 打开串口设备
    int fd = open(device, O_RDWR | O_NOCTTY);
    if (fd < 0) {
        return UART_ERROR_OPEN;
    }
    
    // 设置串口参数
    if (set_termios_options(fd, &final_config) != UART_SUCCESS) {
        close(fd);
        return UART_ERROR_CONFIG;
    }
    
    // 设置缓冲区大小
    if (final_config.flags & UART_FLAG_LARGE_BUFFER) {
        configure_buffer_size(fd, final_config.buffer_size);
    }
    
    // 设置超时
    uart_set_timeout(fd, final_config.timeout_ms);
    
    return fd;
}

/**
 * @brief 关闭UART设备
 * 
 * @param fd 文件描述符
 * @return int 成功返回0，失败返回错误代码
 */
int uart_close_device(int fd) {
    if (fd < 0) {
        return UART_ERROR_INVALID_PARAM;
    }
    
    int ret = close(fd);
    return (ret == 0) ? UART_SUCCESS : UART_ERROR_IO;
}

/**
 * @brief 设置串口缓冲区大小
 * 
 * @param fd 文件描述符
 * @param size 缓冲区大小(字节)
 * @return int 成功返回0，失败返回错误代码
 */
int uart_set_buffer_size(int fd, int size) {
    if (fd < 0 || size <= 0) {
        return UART_ERROR_INVALID_PARAM;
    }
    
    return configure_buffer_size(fd, size);
}

/**
 * @brief 获取串口状态
 * 
 * @param fd 文件描述符
 * @param status 状态结构体指针
 * @return int 成功返回0，失败返回错误代码
 */
int uart_get_device_status(int fd, uart_status_t *status) {
    if (fd < 0 || status == NULL) {
        return UART_ERROR_INVALID_PARAM;
    }
    
    // 检查文件描述符是否有效
    int flags = fcntl(fd, F_GETFL);
    if (flags == -1) {
        status->is_open = 0;
        status->error_code = errno;
        return UART_ERROR_IO;
    }
    
    status->fd = fd;
    status->is_open = 1;
    status->error_code = UART_SUCCESS;
    
    // 获取串口信息
    struct serial_struct ser_info;
    if (ioctl(fd, TIOCGSERIAL, &ser_info) == 0) {
        status->config.buffer_size = ser_info.xmit_fifo_size;
    }
    
    return UART_SUCCESS;
}

/**
 * @brief 清空串口缓冲区
 * 
 * @param fd 文件描述符
 * @param direction 方向 (TCIFLUSH=输入, TCOFLUSH=输出, TCIOFLUSH=双向)
 * @return int 成功返回0，失败返回错误代码
 */
int uart_flush_buffer(int fd, int direction) {
    if (fd < 0) {
        return UART_ERROR_INVALID_PARAM;
    }
    
    int ret = tcflush(fd, direction);
    return (ret == 0) ? UART_SUCCESS : UART_ERROR_IO;
}

/**
 * @brief 设置串口超时
 * 
 * @param fd 文件描述符
 * @param timeout_ms 超时时间(毫秒)
 * @return int 成功返回0，失败返回错误代码
 */
int uart_set_timeout(int fd, int timeout_ms) {
    if (fd < 0 || timeout_ms < 0) {
        return UART_ERROR_INVALID_PARAM;
    }
    
    struct termios options;
    if (tcgetattr(fd, &options) != 0) {
        return UART_ERROR_CONFIG;
    }
    
    // 设置超时参数
    if (timeout_ms == 0) {
        // 非阻塞模式
        options.c_cc[VMIN] = 0;
        options.c_cc[VTIME] = 0;
    } else {
        // 阻塞模式，带超时
        options.c_cc[VMIN] = 0;
        options.c_cc[VTIME] = (timeout_ms + 99) / 100;  // 转换为十分之一秒
    }
    
    int ret = tcsetattr(fd, TCSANOW, &options);
    return (ret == 0) ? UART_SUCCESS : UART_ERROR_CONFIG;
}

/**
 * @brief 设置波特率
 * 
 * @param fd 文件描述符
 * @param baudrate 波特率
 * @return int 成功返回0，失败返回错误代码
 */
static int set_baudrate(int fd, int baudrate) {
    struct termios options;
    if (tcgetattr(fd, &options) != 0) {
        return UART_ERROR_CONFIG;
    }
    
    speed_t speed;
    switch (baudrate) {
        case 9600:   speed = B9600; break;
        case 19200:  speed = B19200; break;
        case 38400:  speed = B38400; break;
        case 57600:  speed = B57600; break;
        case 115200: speed = B115200; break;
        case 230400: speed = B230400; break;
        case 460800: speed = B460800; break;
        case 921600: speed = B921600; break;
        default:
            // 尝试使用cfsetispeed/cfsetospeed设置自定义波特率
            if (cfsetispeed(&options, baudrate) != 0 || cfsetospeed(&options, baudrate) != 0) {
                return UART_ERROR_CONFIG;
            }
            return UART_SUCCESS;
    }
    
    if (cfsetispeed(&options, speed) != 0 || cfsetospeed(&options, speed) != 0) {
        return UART_ERROR_CONFIG;
    }
    
    int ret = tcsetattr(fd, TCSANOW, &options);
    return (ret == 0) ? UART_SUCCESS : UART_ERROR_CONFIG;
}

/**
 * @brief 设置termios选项
 * 
 * @param fd 文件描述符
 * @param config 串口配置
 * @return int 成功返回0，失败返回错误代码
 */
static int set_termios_options(int fd, const uart_config_t *config) {
    struct termios options;
    if (tcgetattr(fd, &options) != 0) {
        return UART_ERROR_CONFIG;
    }
    
    // 设置波特率
    if (set_baudrate(fd, config->baudrate) != UART_SUCCESS) {
        return UART_ERROR_CONFIG;
    }
    
    // 设置数据位
    options.c_cflag &= ~CSIZE;
    switch (config->data_bits) {
        case 5: options.c_cflag |= CS5; break;
        case 6: options.c_cflag |= CS6; break;
        case 7: options.c_cflag |= CS7; break;
        case 8: options.c_cflag |= CS8; break;
        default: options.c_cflag |= CS8; break;
    }
    
    // 设置停止位
    if (config->stop_bits == 2) {
        options.c_cflag |= CSTOPB;
    } else {
        options.c_cflag &= ~CSTOPB;
    }
    
    // 设置校验位
    if (config->parity == 0) {
        options.c_cflag &= ~PARENB;  // 无校验
    } else {
        options.c_cflag |= PARENB;   // 有校验
        if (config->parity == 1) {
            options.c_cflag |= PARODD;  // 奇校验
        } else {
            options.c_cflag &= ~PARODD; // 偶校验
        }
    }
    
    // 设置流控制
    if (config->flow_control == 0) {
        // 无流控制
        options.c_iflag &= ~(IXON | IXOFF | IXANY);
        options.c_cflag &= ~CRTSCTS;
    } else if (config->flow_control == 1) {
        // 软件流控制
        options.c_iflag |= (IXON | IXOFF | IXANY);
        options.c_cflag &= ~CRTSCTS;
    } else if (config->flow_control == 2) {
        // 硬件流控制
        options.c_iflag &= ~(IXON | IXOFF | IXANY);
        options.c_cflag |= CRTSCTS;
    }
    
    // 基本控制模式
    options.c_cflag |= (CLOCAL | CREAD);
    
    // 输入模式设置
    options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL);
    
    // 输出模式设置
    options.c_oflag &= ~OPOST;
    
    // 本地模式设置
    if (config->flags & UART_FLAG_RAW_MODE) {
        options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    } else {
        options.c_lflag |= ICANON;
    }
    
    // 应用设置
    int ret = tcsetattr(fd, TCSANOW, &options);
    return (ret == 0) ? UART_SUCCESS : UART_ERROR_CONFIG;
}

/**
 * @brief 配置缓冲区大小
 * 
 * @param fd 文件描述符
 * @param target_size 目标缓冲区大小
 * @return int 成功返回0，失败返回错误代码
 */
static int configure_buffer_size(int fd, int target_size) {
    struct serial_struct ser_info;
    if (ioctl(fd, TIOCGSERIAL, &ser_info) != 0) {
        return UART_ERROR_CONFIG;
    }
    
    int original_size = ser_info.xmit_fifo_size;
    
    // 修改发送缓冲区大小（Linux 串口结构仅支持 xmit_fifo_size）
    ser_info.xmit_fifo_size = target_size;
    
    // 尝试应用新的缓冲区设置
    if (ioctl(fd, TIOCSSERIAL, &ser_info) != 0) {
        // 如果设置失败，恢复原始大小
        ser_info.xmit_fifo_size = original_size;
        return UART_ERROR_CONFIG;
    }
    
    return UART_SUCCESS;
} 